Skip to content

Conversation

@ammar-agent
Copy link
Collaborator

@ammar-agent ammar-agent commented Oct 19, 2025

Problem

When the "Uncommitted" checkbox is enabled in the Code Review panel, uncommitted filesystem changes don't appear correctly.

Root cause: The implementation used git diff base...HEAD && git diff HEAD, which produced TWO separate diff outputs for the same file with different base states, creating confusing UX where hunks reference different contexts.

Solution

Generate cleaner git commands that produce unified diffs.

Command Generation Logic

if (diffBase === "--staged") {
  // Show staged changes, optionally append unstaged
  cmd = `git diff --staged...`;
  if (includeUncommitted) cmd += ` && git diff HEAD...`;
} else if (diffBase === "HEAD") {
  // Already shows uncommitted (no change needed)
  cmd = `git diff HEAD...`;
} else {
  // Branch diffs
  if (includeUncommitted) {
    cmd = `git diff ${diffBase}...`;  // Two-dot: base to working (unified)
  } else {
    cmd = `git diff ${diffBase}...HEAD...`;  // Three-dot: committed only
  }
}

Git Diff Types

  • Three-dot (base...HEAD): Shows only committed changes
  • Two-dot (base): Shows all changes from base to working directory (unified view)

When includeUncommitted=true for branch diffs, we now use two-dot to get a single, cohesive diff showing all changes.

Benefits

Cleaner UX - Single unified diff instead of fragmented hunks
Fixes root cause - Not just papering over symptoms
Simpler code - Net -5 LoC (removed unnecessary deduplication)
Better mental model - Matches user expectation of "show me all my changes"

Testing (TDD)

  1. Updated test to verify single FileDiff with unified changes
  2. Added test for --staged edge case (should still produce two diffs: staged + unstaged)
  3. Fixed test to work with any default branch name (not hardcoded 'main')

Results:

  • 13/13 diffParser tests pass ✅
  • 629/629 total tests pass ✅
  • Types check ✅

Tests use buildGitDiffCommand directly from implementation to ensure we're testing the real integration.

Impact

  • Net -5 LoC (command logic +10, removed deduplication -15)
  • 3 files changed: ReviewPanel.tsx, diffParser.ts, diffParser.test.ts

Generated with cmux

When 'Dirty' checkbox is enabled, uncommitted filesystem changes
were not appearing in the code review panel. Root cause: combining
git commands with && (e.g., 'git diff base...HEAD && git diff HEAD')
produces duplicate FileDiff entries for the same file.

The parser was creating separate FileDiff objects for each, meaning:
- File tree showed files twice (or one overwrote the other)
- Hunks from both diffs contributed to the list
- But file filtering only matched hunks from the FIRST entry

Solution: Deduplicate FileDiff entries by file path after parsing,
merging hunks from duplicate entries into a single canonical entry.

This makes the parser more robust and ensures all hunks (committed
and uncommitted) appear when filtering by file.

Test approach (TDD):
1. Added failing test demonstrating duplicate FileDiff bug
2. Implemented deduplication logic in parseDiff()
3. Verified all tests pass (12 diffParser tests, 628 total tests)

_Generated with `cmux`_
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Instead of deduplicating FileDiff entries after parsing, fix the root
cause by generating better git commands.

**Problem with old approach:**
- Used `git diff base...HEAD && git diff HEAD` when includeUncommitted=true
- Created TWO separate diffs for same file with different base hashes
- Resulted in confusing UX (separate hunks with different contexts)

**New approach:**
- When includeUncommitted=true for branch diffs: use TWO-DOT diff
  (`git diff base`) to show unified changes from base to working directory
- For --staged: keep && behavior (staged + unstaged shown separately)
- For HEAD: no change needed (already shows uncommitted)

**Result:**
- Single unified diff showing all changes cleanly
- No duplicate FileDiff entries
- Better UX - reviewers see cohesive changes, not fragmented hunks
- Net -5 LoC (simpler codebase)

**Testing:**
- Updated test to verify single FileDiff with unified changes
- Added test for --staged edge case (should still use &&)
- All 629 tests pass ✅
- Types check ✅

_Generated with `cmux`_
The test was falling back to hardcoded 'main' which fails on systems
where git init creates 'master' by default.

Fix: Get the current branch name before checking out the new branch,
avoiding reliance on upstream tracking or hardcoded branch names.

_Generated with `cmux`_
@ammar-agent ammar-agent changed the title 🤖 Fix uncommitted changes not showing with 'Dirty' checkbox 🤖 Fix uncommitted changes display using unified git diff Oct 19, 2025
_Generated with `cmux`_
Added comprehensive documentation to buildGitDiffCommand explaining:
- Three-dot vs two-dot diff behavior
- Why each case uses different git commands
- What includeUncommitted means in each context
- Examples for each scenario

This makes the logic clearer for future maintainers.

_Generated with `cmux`_
@ammario ammario enabled auto-merge October 19, 2025 03:25
@ammario ammario added this pull request to the merge queue Oct 19, 2025
- Condensed buildGitDiffCommand logic (removed redundant comments)
- Simplified test assertions and comments
- Added test for includeUncommitted=false (three-dot diff) case
- Net -30 lines, clearer code
@ammario ammario removed this pull request from the merge queue due to a manual request Oct 19, 2025
@ammario ammario enabled auto-merge October 19, 2025 03:32
@ammario ammario added this pull request to the merge queue Oct 19, 2025
Merged via the queue into main with commit 70946af Oct 19, 2025
8 checks passed
@ammario ammario deleted the fix-dirty-duplicates branch October 19, 2025 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants